iT邦幫忙

2026 iThome 鐵人賽

0
Build on Google AI

將考國際證照的應用程式變成開源系列 第 76 篇

GCP 實戰筆記:Cloud Storage 與 Cloud SQL 整合應用

  • 分享至 

  • xImage
  •  

GCP 實戰筆記:Cloud Storage 與 Cloud SQL 整合應用

實驗目標與架構

  1. Compute Engine (VM):建立一台運行 Debian 的 VM (bloghost),透過啟動腳本自動安裝 Apache 與 PHP 環境,並開啟 HTTP (80) 防火牆。
  2. Cloud Storage (GCS):建立以 Project ID 命名的 Bucket,下載並上傳範例圖片,設定公開存取權限(allUsers:R)。
  3. Cloud SQL (MySQL):建立受管 MySQL 實例 (blog-db),建立專用使用者,並設定授權網路允許 VM 的 External IP 存取。
  4. 應用程式串接:在 VM 上建立 index.php,整合 GCS 圖片與 Cloud SQL 資料庫連線,驗證網頁正常顯示與連線成功。

完整 CLI 操作流程

Step 0. 環境變數設定

開啟 Cloud Shell 後,預先定義本次實驗分配到的區域與地理位置:

# 根據實驗手冊提示設定對應的 Region 與 Zone
export REGION=us-east4
export ZONE=us-east4-b
export LOCATION=US


Step 1. 部署 Web Server VM 與防火牆規則

透過 startup-script 在開機時自動安裝 Apache2 與 PHP MySQL 模組,並加上 http-server 網路標籤:

# 1. 建立 VM Instance
gcloud compute instances create bloghost \
  --project=$DEVSHELL_PROJECT_ID \
  --zone=$ZONE \
  --machine-type=e2-standard-2 \
  --image-family=debian-12 \
  --image-project=debian-cloud \
  --tags=http-server \
  --metadata=startup-script='#!/bin/bash
apt-get install apache2 php php-mysql -y
service apache2 restart'

# 2. 建立防火牆規則允許 HTTP (Port 80)
gcloud compute firewall-rules create default-allow-http \
  --project=$DEVSHELL_PROJECT_ID \
  --direction=INGRESS \
  --priority=1000 \
  --network=default \
  --action=ALLOW \
  --rules=tcp:80 \
  --target-tags=http-server

# 3. 取得並暫存 VM 的外部公用 IP
VM_EXT_IP=$(gcloud compute instances describe bloghost \
  --zone=$ZONE \
  --format='get(networkInterfaces[0].accessConfigs[0].natIP)')
echo "VM External IP: $VM_EXT_IP"


Step 2. 建立 Cloud Storage Bucket 與託管靜態圖片

Bucket 名稱需全球唯一,本實驗使用預設環境變數 $DEVSHELL_PROJECT_ID 作為名稱:

# 1. 建立 Storage Bucket
gcloud storage buckets create -l $LOCATION gs://$DEVSHELL_PROJECT_ID

# 2. 下載範例圖片至 Cloud Shell 本地
gcloud storage cp gs://cloud-training/gcpfci/my-excellent-blog.png my-excellent-blog.png

# 3. 上傳圖片至建立的 Bucket
gcloud storage cp my-excellent-blog.png gs://$DEVSHELL_PROJECT_ID/my-excellent-blog.png

# 4. 修改物件 ACL,將該圖片設為公開讀取
gsutil acl ch -u allUsers:R gs://$DEVSHELL_PROJECT_ID/my-excellent-blog.png


Step 3. 建立 Cloud SQL (MySQL) 實例與授權網路

建立 MySQL 8.0 實例,設定專用帳號,並將 VM 的對外 IP 加入白名單:

# 1. 建立 Cloud SQL Instance(注意:僅指定 --zone,勿同時指定 --region)
gcloud sql instances create blog-db \
  --project=$DEVSHELL_PROJECT_ID \
  --database-version=MYSQL_8_0 \
  --zone=$ZONE \
  --tier=db-custom-2-7680 \
  --root-password="Passw0rd1!"

# 2. 建立資料庫使用者 blogdbuser
gcloud sql users create blogdbuser \
  --instance=blog-db \
  --password="Passw0rd1!"

# 3. 授權 VM 的外部 IP (以 /32 CIDR 格式) 連線至 Cloud SQL
gcloud sql instances patch blog-db \
  --authorized-networks="${VM_EXT_IP}/32"

# 4. 取得並暫存 Cloud SQL 的公用 IP
SQL_IP=$(gcloud sql instances describe blog-db \
  --format='get(ipAddresses[0].ipAddress)')
echo "Cloud SQL IP: $SQL_IP"


Step 4. 產生 PHP 網頁並部署至 VM

在 Cloud Shell 本地透過 Here-Doc 生成網頁程式碼,透過 sed 替換動態 IP 與專案 ID,再使用 scp 與 ssh 佈署到 VM:

# 1. 在本地建立包含 GCS 圖片與 PDO 資料庫連線的 index.php 範本
cat <<'EOF' > index.php
<html>
<head><title>Welcome to my excellent blog</title></head>
<body>
<img src="https://storage.googleapis.com/PROJECT_ID/my-excellent-blog.png">
<h1>Welcome to my excellent blog</h1>
<?php
 $dbserver = "SQL_IP";
 $dbuser = "blogdbuser";
 $dbpassword = "Passw0rd1!";

 try {
  $conn = new PDO("mysql:host=$dbserver;dbname=mysql", $dbuser, $dbpassword);
  $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  echo "Connected successfully";
} catch(PDOException $e) {
  echo "Database connection failed:: " . $e->getMessage();
}
?>
</body></html>
EOF

# 2. 替換專案 ID 與 Cloud SQL IP 變數
sed -i "s/PROJECT_ID/$DEVSHELL_PROJECT_ID/g" index.php
sed -i "s/SQL_IP/$SQL_IP/g" index.php

# 3. 將檔案傳送至 bloghost VM 並放置到 /var/www/html/,最後重啟 Apache
gcloud compute scp index.php bloghost:/tmp/index.php --zone=$ZONE
gcloud compute ssh bloghost --zone=$ZONE --command="sudo mv /tmp/index.php /var/www/html/index.php && sudo systemctl restart apache2"


Step 5. 終端驗證

直接在 Cloud Shell 發送 HTTP 請求驗證整合狀態:

curl http://$VM_EXT_IP/index.php

預期輸出結果:

<html>
<head><title>Welcome to my excellent blog</title></head>
<body>
<img src="https://storage.googleapis.com/<YOUR_PROJECT_ID>/my-excellent-blog.png">
<h1>Welcome to my excellent blog</h1>
Connected successfully</body></html>


核心注意事項與踩坑重點 (Troubleshooting)

  1. Cloud SQL 指令參數衝突
  • 問題:若同時傳入 --region 與 --zone,CLI 會報錯:argument --region: At most one of --region | --gce-zone | --secondary-zone --zone can be specified.。
  • 解法:在建立單一區域實例時,僅需指定 --zone=$ZONE,系統會自動匹配對應 Region。
  1. Bash 驚嘆號擴展問題 (History Expansion)
  • 問題:在 Bash 雙引號字串中直接使用包含 ! 的密碼(如 "Passw0rd1!")會觸發歷史事件解析,出現 -bash: !: event not found,導致密碼被清空(PHP 出現 using password: NO 錯誤)。
  • 解法:建立指令檔時使用單引號標籤(cat <<'EOF')阻斷終端解析,或將檔案先寫在本地再用 scp 傳送至 VM。
  1. Cloud SQL 授權網路格式
  • 授權特定主機 IP 時,必須附加子網路遮罩 /32(例如 136.107.121.62/32),否則 API 會回報無效格式。

上一篇
理解 VPC 網路架構、自動模式子網(Auto mode subnets)、防火牆規則機制,以及 Compute Engine VM 實例之間的網路連線性
下一篇
Google Cloud 的全代管無伺服器(Serverless)運算平台
系列文
將考國際證照的應用程式變成開源 共 77 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言